package cx.cs.springframework.beans.factory.support;


import cx.cs.springframework.beans.BeansException;
import cx.cs.springframework.beans.PropertyValue;
import cx.cs.springframework.beans.PropertyValues;
import cx.cs.springframework.beans.factory.config.BeanDefinition;
import cx.cs.springframework.beans.factory.config.BeanReference;
import cx.cs.springframework.beans.util.BeanUtil;


import java.lang.reflect.Constructor;


/*
提供bean创建的核心逻辑
核心功能：
createBean() 方法：
使用反射（newInstance()）创建 Bean 实例。
将创建的 Bean 注册到单例缓存（通过 addSingleton()）。
异常处理：将反射异常（InstantiationException、IllegalAccessException）包装为运行时异常。
*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();


    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition,Object[] args) throws BeansException {
        Object bean = null;
        try{
            bean = CreateBeanInstance(beanName, beanDefinition, args);
            applyPropertyValues(bean,beanDefinition);
        }catch (Exception e){
            throw new BeansException("Unable to create bean " + beanName, e);
        }
        addSingleton(beanName,bean);
        return bean;
    }

    protected Object CreateBeanInstance(String beanName, BeanDefinition beanDefinition,Object[] args) throws BeansException {
        Constructor constructor = null;
        Class<?> beanClass = beanDefinition.getBeanClass();
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        for (Constructor constructor1 : declaredConstructors) {
            if(null != args && args.length == constructor1.getParameterCount()) {
                constructor = constructor1;
                break;
            }
        }
        return getInstantiationStrategy().instantiate(beanDefinition,beanName,constructor,args);
    }

    protected void applyPropertyValues(Object bean, BeanDefinition beanDefinition){
        try{
            PropertyValues PropertyValues = beanDefinition.getPropertyValues();
            for (PropertyValue propertyValue : PropertyValues.getPropertyValues()){
                String name = propertyValue.getName();
                System.out.println(name);
                Object value = propertyValue.getValue();
                System.out.println(value);
                if(value instanceof BeanReference){
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                BeanUtil.setFieldValue(bean,name,value);
            }
        } catch (BeansException e) {
            throw new RuntimeException(e);
        }
    }


    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }
}
